package location;

import encounter.Encounter;
import encounter.Lootable;
import encounter.NoopEncounter;
import item.Item;
import main.Hero;
import main.Logger;
import main.RandomList;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.google.common.collect.Lists.newArrayList;

public class BasicLocation implements Location {
    private final String name;

    private final transient List<Location> exits = newArrayList();
    private final transient RandomList<Encounter> encounters;

    private final transient List<Item> items = new ArrayList<>();

    public BasicLocation(String name, Map<Encounter, Integer> encounterTargets, Optional<Location> origin) {
        this.name = name;

        origin.ifPresent(exits::add);

        encounters = new RandomList<>();
        encounters.add(new NoopEncounter(), 100);

        for (Encounter encounter : encounterTargets.keySet()) {
            encounters.add(encounter, encounterTargets.get(encounter));
            if (encounter instanceof Lootable) {
                this.items.addAll(((Lootable) encounter).getPossibleLoot());
            }
        }
    }

    @Override
    public boolean isVillage() {
        return false;
    }

    @Override
    public List<Location> getExits() {
        return exits;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void visit(Hero hero) {
        if (hero.getHealth() <= 3 || hero.getEnergy() < 0.25 || hero.getRescue().isPresent()) {
            Logger.log(this + " decides to return to village. Heatlh: " + hero.getHealth() + "; energy: " + hero.getEnergy() + ".");
            for (Location exit : this.getExits()) {
                if (exit.isVillage()) {
                    hero.addEvent("Goes to " + exit + ".");
                    hero.moveTo(exit);
                    hero.updateEnergy(-0.01);
                    return;
                }
            }
        }

        Encounter encounter = this.encounters.getElement();
        if (encounter.resolve(hero)) {
            this.encounters.remove(encounter, 1);
        }
    }

    @Override
    public void process() {
        // nothing here yet
    }

    @Override
    public void addEncounter(Encounter encounter, int weight) {
        encounters.add(encounter, weight);
    }

    @Override
    public List<Item> getItems() {
        return this.items;
    }

    @Override
    public String toString() {
        return this.getName();
    }
}
